package org.linlinjava.litemall.core.qcode;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.google.common.collect.Lists;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.iherus.codegen.qrcode.SimpleQrcodeGenerator;
import org.linlinjava.litemall.core.storage.StorageService;
import org.linlinjava.litemall.core.system.SystemConfig;
import org.linlinjava.litemall.core.util.CommonUtils;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.LitemallGroupon;
import org.linlinjava.litemall.db.domain.LitemallStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;

@Service
public class QCodeService {
    private final Log logger = LogFactory.getLog(QCodeService.class);
    @Autowired
    WxMaService wxMaService;

    @Autowired
    private StorageService storageService;

    @Transactional
    public Object createActivityGrouponShareImage(String url) {
        try {
            BufferedImage image = new SimpleQrcodeGenerator().generate(url).getImage();

            BufferedImage result = new BufferedImage(image.getWidth(), image
                    .getHeight(), BufferedImage.TYPE_3BYTE_BGR);
            result.getGraphics().drawImage(image, 0, 0, null);
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageIO.write(result, "jpg", bs);
            byte[] bytes = bs.toByteArray();

            BASE64Encoder encoder = new BASE64Encoder();
            return ResponseUtil.ok(encoder.encode(bytes));
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return ResponseUtil.fail();
    }

    public Object createActivityGrouponShareBase64(String url, String homePicUrl, String desc, String nickName, String avatar) {
        try {
            BufferedImage image = new SimpleQrcodeGenerator().generate(url).getImage();

            BufferedImage result = new BufferedImage(image.getWidth(), image
                    .getHeight(), BufferedImage.TYPE_3BYTE_BGR);
            result.getGraphics().drawImage(image, 0, 0, null);
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageIO.write(result, "jpg", bs);

            byte[] bytes = bs.toByteArray();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);

            byte[] imageData = drawActivityPicture(inputStream, homePicUrl, desc, nickName, avatar);

            BASE64Encoder encoder = new BASE64Encoder();
            return ResponseUtil.ok(encoder.encode(imageData));
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
        return ResponseUtil.fail();
    }

    public String createGrouponShareImage(String goodName, String goodPicUrl, LitemallGroupon groupon) {
        try {
            //创建该商品的二维码
            File file = wxMaService.getQrcodeService().createWxaCodeUnlimit("groupon," + groupon.getId(), "pages" +
                    "/index/index");
            FileInputStream inputStream = new FileInputStream(file);
            //将商品图片，商品名字,商城名字画到模版图中
            byte[] imageData = drawPicture(inputStream, goodPicUrl, goodName);
            ByteArrayInputStream inputStream2 = new ByteArrayInputStream(imageData);
            //存储分享图
            LitemallStorage storageInfo = storageService.store(inputStream2, imageData.length, "image/jpeg",
                    getKeyName(groupon.getId().toString()));

            return storageInfo.getUrl();
        } catch (WxErrorException e) {
            logger.error(e.getMessage(), e);
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }

        return "";
    }


    /**
     * 创建商品分享图
     *
     * @param goodId
     * @param goodPicUrl
     * @param goodName
     */
    public String createGoodShareImage(String goodId, String goodPicUrl, String goodName) {
        if (!SystemConfig.isAutoCreateShareImage())
            return "";

        try {
            //创建该商品的二维码
            File file = wxMaService.getQrcodeService().createWxaCodeUnlimit("goods," + goodId, "pages/index/index");
            FileInputStream inputStream = new FileInputStream(file);
            //将商品图片，商品名字,商城名字画到模版图中
            byte[] imageData = drawPicture(inputStream, goodPicUrl, goodName);
            ByteArrayInputStream inputStream2 = new ByteArrayInputStream(imageData);
            //存储分享图
            LitemallStorage litemallStorage = storageService.store(inputStream2, imageData.length, "image/jpeg",
                    getKeyName(goodId));

            return litemallStorage.getUrl();
        } catch (WxErrorException e) {
            logger.error(e.getMessage(), e);
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }

        return "";
    }

    private String getKeyName(String goodId) {
        return "GOOD_QCODE_" + goodId + ".jpg";
    }

    private byte[] drawActivityPicture(InputStream qrCodeImg, String homePicUrl, String desc, String nickName, String avatar) throws IOException {
        //底图
        ClassPathResource redResource = new ClassPathResource("back.png");
        BufferedImage red = ImageIO.read(redResource.getInputStream());

        //活动首页图片url
        URL homePic = new URL(homePicUrl);
        BufferedImage homePicImage = ImageIO.read(homePic);

        //二维码
        BufferedImage qrCodeImage = ImageIO.read(qrCodeImg);

        //用户头像
        URL avatarUrl = new URL(avatar);
        BufferedImage avatarImage = ImageIO.read(avatarUrl);

        // --- 画图 ---

        //底层空白 bufferedImage
        BufferedImage baseImage = new BufferedImage(red.getWidth(), red.getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE);

        Color color = new Color(0, 0, 0);

        //画上图片
        drawImgInImgNew(baseImage, red, 0, 0, red.getWidth(), red.getHeight(), 1F);

        //画上活动首页url图片
        drawImgInImgNew(baseImage, homePicImage, 71, 69, 660, 660, 1F);

        // 画上二维码
        drawImgInImgNew(baseImage, qrCodeImage, 448, 870, 230, 230, 1F);

        //写上海报文案
        drawTextInImg(color, Font.BOLD, baseImage, desc, 63, 750, 680, 660);

        // 画上用户头像
        drawImgInImgNew(baseImage, avatarImage, 63, 960, 100, 100, 0.3F);

        // 写上用户名
        drawTextInImg(new Color(110, 110, 110), Font.PLAIN, baseImage, nickName.length() > 6 ? CommonUtils.getPingbStr(nickName, 6) : nickName, 180, 925, 300, 300);
        // 写上用户名
        drawTextInImg(new Color(110, 110, 110), Font.PLAIN, baseImage, "正在参加", 180, 960, 300, 300);

        //转jpg
        BufferedImage result = new BufferedImage(baseImage.getWidth(), baseImage
                .getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        result.getGraphics().drawImage(baseImage, 0, 0, null);
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ImageIO.write(result, "jpg", bs);

        //最终byte数组
        return bs.toByteArray();
    }


    /**
     * 将商品图片，商品名字画到模版图中
     *
     * @param qrCodeImg  二维码图片
     * @param goodPicUrl 商品图片地址
     * @param goodName   商品名称
     * @return
     * @throws IOException
     */
    private byte[] drawPicture(InputStream qrCodeImg, String goodPicUrl, String goodName) throws IOException {
        //底图
        ClassPathResource redResource = new ClassPathResource("back.png");
        BufferedImage red = ImageIO.read(redResource.getInputStream());


        //商品图片
        URL goodPic = new URL(goodPicUrl);
        BufferedImage goodImage = ImageIO.read(goodPic);

        //小程序二维码
        BufferedImage qrCodeImage = ImageIO.read(qrCodeImg);

        // --- 画图 ---

        //底层空白 bufferedImage
        BufferedImage baseImage = new BufferedImage(red.getWidth(), red.getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE);
        Color color = new Color(0, 0, 0);

        //画上图片
        drawImgInImg(baseImage, red, 0, 0, red.getWidth(), red.getHeight());

        //画上商品图片
        drawImgInImg(baseImage, goodImage, 71, 69, 660, 660);

        //画上小程序二维码
        drawImgInImg(baseImage, qrCodeImage, 448, 767, 300, 300);

        //写上商品名称
        drawTextInImg(color, Font.PLAIN, baseImage, goodName, 65, 867, 300, 300);

        //写上商城名称
        //        drawTextInImgCenter(baseImage, shopName, 98);


        //转jpg
        BufferedImage result = new BufferedImage(baseImage.getWidth(), baseImage
                .getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        result.getGraphics().drawImage(baseImage, 0, 0, null);
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ImageIO.write(result, "jpg", bs);

        //最终byte数组
        return bs.toByteArray();
    }

    private void drawTextInImgCenter(BufferedImage baseImage, String textToWrite, int y) {
        Graphics2D g2D = (Graphics2D) baseImage.getGraphics();
        g2D.setColor(new Color(167, 136, 69));

        String fontName = "Microsoft YaHei";

        Font f = new Font(fontName, Font.PLAIN, 28);
        g2D.setFont(f);
        g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 计算文字长度，计算居中的x点坐标
        FontMetrics fm = g2D.getFontMetrics(f);
        int textWidth = fm.stringWidth(textToWrite);
        int widthX = (baseImage.getWidth() - textWidth) / 2;
        // 表示这段文字在图片上的位置(x,y) .第一个是你设置的内容。

        g2D.drawString(textToWrite, widthX, y);
        // 释放对象
        g2D.dispose();
    }

    private void drawTextInImg(Color color, int fontStyle, BufferedImage baseImage, String textToWrite, int x, int y, int width, int height) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String[] fontList = ge.getAvailableFontFamilyNames();
        for (String s : fontList) {
            logger.info("字体----:" + s);
        }

        Graphics2D g2D = (Graphics2D) baseImage.getGraphics();
        g2D.setColor(color);

        java.util.List<String> lineList = Lists.newArrayList();
        //TODO 注意，这里的字体必须安装在服务器上
        Font font = new Font("Microsoft YaHei", fontStyle, 32);

        g2D.setFont(font);
        g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        FontRenderContext frc = g2D.getFontRenderContext();
        Rectangle2D stringBounds = font.getStringBounds(textToWrite, frc);
        double fontWidth = stringBounds.getWidth();
        if (fontWidth <= width) {
            lineList.add(textToWrite);
        } else {
            int textWidth = width;//输出文本宽度,这里就以画布宽度作为文本宽度测试
            double bs = fontWidth / textWidth;//文本长度是文本框长度的倍数
            int lineCharCount = (int) Math.ceil(textToWrite.length() / bs);//每行大概字数
            int beginIndex = 0;
            while (beginIndex < textToWrite.length()) {
                int endIndex = beginIndex + lineCharCount;
                if (endIndex >= textToWrite.length()) {
                    endIndex = textToWrite.length();
                }
                String lineStr = textToWrite.substring(beginIndex, endIndex);
                Rectangle2D tempStringBounds = font.getStringBounds(lineStr, frc);

                int tzzs = 1;//调整字数,临时文本的字符串长度大于要求的文本宽度时,每次减少临时文本的字数,然后重新测量文本宽度
                while (tempStringBounds.getWidth() > textWidth) {
                    lineStr = lineStr.substring(0, lineStr.length() - tzzs);//每次向前 tzzs 个字符重新计算(待优化)
                    tempStringBounds = font.getStringBounds(lineStr, frc);
                }
                lineList.add(lineStr);
                beginIndex = beginIndex + lineStr.length();
            }
        }

        for (int i = 0; i < lineList.size(); i++) {
            String lineStr = lineList.get(i);
            g2D.drawString(lineStr, x, y + (i + 2) * 35);//35为每行的高度
        }
        g2D.dispose();
    }

    private void drawImgInImg(BufferedImage baseImage, BufferedImage imageToWrite, int x, int y, int width,
                              int heigth) {
        Graphics2D g2D = (Graphics2D) baseImage.getGraphics();
        g2D.drawImage(imageToWrite, x, y, width, heigth, null);
        g2D.dispose();
    }

    private void drawImgInImgNew(BufferedImage baseImage, BufferedImage imageToWrite, int x, int y, int width,
                                 int heigth, float scale) {
        Graphics2D g2D = (Graphics2D) baseImage.getGraphics();
        int picWidth = 450;
        int picHeight = 300;
        if (scale != 1F) {
            picWidth = new Float(picWidth * scale).intValue();
            picHeight = new Float(picHeight * scale).intValue();
        }
        g2D.drawImage(imageToWrite.getScaledInstance(picWidth, picHeight, Image.SCALE_SMOOTH), x, y, width, heigth, null);
        g2D.dispose();
    }

}
